package com.bill99mpp.demo.rsa;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;

public class IndefiniteLengthInputStream extends LimitedInputStream {
	private int _b1;
	private int _b2;
	private boolean _eofReached = false;
	private boolean _eofOn00 = true;

	IndefiniteLengthInputStream(InputStream in, int limit) throws IOException {
		super(in, limit);

		_b1 = in.read();
		_b2 = in.read();

		if (_b2 < 0) {
			// Corrupted stream
			throw new EOFException();
		}

		checkForEof();
	}

	void setEofOn00(boolean eofOn00) {
		_eofOn00 = eofOn00;
		checkForEof();
	}

	private boolean checkForEof() {
		if (!_eofReached && _eofOn00 && (_b1 == 0x00 && _b2 == 0x00)) {
			_eofReached = true;
			setParentEofDetect(true);
		}
		return _eofReached;
	}

	public int read(byte[] b, int off, int len) throws IOException {
		// Only use this optimisation if we aren't checking for 00
		if (_eofOn00 || len < 3) {
			return super.read(b, off, len);
		}

		if (_eofReached) {
			return -1;
		}

		int numRead = _in.read(b, off + 2, len - 2);

		if (numRead < 0) {
			// Corrupted stream
			throw new EOFException();
		}

		b[off] = (byte) _b1;
		b[off + 1] = (byte) _b2;

		_b1 = _in.read();
		_b2 = _in.read();

		if (_b2 < 0) {
			// Corrupted stream
			throw new EOFException();
		}

		return numRead + 2;
	}

	public int read() throws IOException {
		if (checkForEof()) {
			return -1;
		}

		int b = _in.read();

		if (b < 0) {
			throw new EOFException();
		}

		int v = _b1;

		_b1 = _b2;
		_b2 = b;

		return v;
	}
}
